var sw = 20,  //一个方块的宽度
	sh = 20,  //一个方块的高度
    tr = 30,  //行数
	td = 30;  //列数
	
var snake = null,  //申明蛇的实例
    food = null,   //声明食物
	game = null;
		
/* 方块构建函数，snakeHead，snakeBody，food */
function Square(x,y,classname){
		this.x = x*sw;
		this.y = y*sh;
		this.class = classname;
		
		/* 把对象的class属性添加到创建的div中 */
		this.viewContent = document.createElement("div");  //方块对应的DOM元素
		this.viewContent.className = this.class;
		this.parent = document.getElementById("snakeWrap"); //方块父级
	}


/* 利用原型对象，创建方块DOM，使对象实例snakeHead，snakeBody，food都可以使用对应属性 */
Square.prototype.create = function(){
	this.viewContent.style.position = "absolute";
	this.viewContent.style.width = sw +"px";
	this.viewContent.style.height = sh +"px";
	this.viewContent.style.left = this.x +"px";
	this.viewContent.style.top = this.y +"px";
	
	/* 把新建的viewContent(div)添加到this.parent(snakeWrap)中 */
	this.parent.appendChild(this.viewContent);
};

/* 利用原型对象，删除方块DOM */
Square.prototype.remove = function(){
	this.parent.removeChild(this.viewContent); 
};

//蛇  (蛇移动时，只移动了蛇头和蛇尾)
function Snake(){
	this.head = null;        //存储蛇头的信息
	this.tail = null;        //存储蛇尾的信息
	this.pos=[];        //存储蛇身上的每一个方块位置，二维数组
	this.directionNum = {    //存储行走的方向，用一个对象来表示
		left:{
			x:-1,      //left是directionNum的属性,{x:-1,y:0}是属性值，也是对象 ，x是对象{x:-1,y:0}的属性，-1是属性值
			y:0,
			rotate:180     //蛇头在不同的方向应该秀旋转
		},
		right:{
			x:1,
			y:0,
			rotate:0
		},
		up:{
			x:0,
			y:-1,
			rotate:-90
		},
		down:{
			x:0,
			y:1,
			rotate:90
		}
	}; 
};

Snake.prototype.init = function(){     //蛇的初始化
	//创建蛇头
	var snakeHead = new Square(2,0,"snakeHead");
	snakeHead.create();
	this.head = snakeHead;   //存储蛇头信息
	this.pos.push([2,0]);   //push() 方法可向数组的末尾添加一个或多个元素，并返回新的长度。  unshift() 方法可向数组的开头添加一个或更多元素，并返回新的长度。  splice(下标,替换个数,替换内容),可以增删改数据,下标操作   shift() 方法可向数组的开头删除一个或更多元素，并返回新的长度。pop()方法可以在数组最后面删除一个元素
	
	//创建蛇身体1
	var snakeBody1 = new Square(1,0,"snakeBody");
	snakeBody1.create();
	this.pos.push([1,0]);   //把蛇身1的坐标存储一下
	
	//创建蛇身体2
	var snakeBody2 = new Square(0,0,"snakeBody");
	snakeBody2.create();
	this.tail = snakeBody2; //存储蛇尾信息
	this.pos.push([0,0]);   //把蛇身2的坐标存储一下
	
	//形成链表关系
	snakeHead.last = null;
	snakeHead.first = snakeBody1;
	
	snakeBody1.last = snakeHead;
	snakeBody1.first = snakeBody2;
	
	snakeBody2.last = snakeBody1;
	snakeBody1.first = null;
	
	//给蛇添加一条属性，用来表示蛇走的方向
	this.direction = this.directionNum.right; //默认让蛇往右走
};

//创建一个方法，用来获取蛇头的下一个位置对应的元素,要根据元素做不同的位置
Snake.prototype.getNextPos = function(){
	var nextPos = [        //蛇头要走的下一个点的坐标
		this.head.x/sw + this.direction.x,
		this.head.y/sh + this.direction.y
	]
	
	//下一个点是自己，撞到了自己，游戏结束
	var selfCollied = false;   //是否撞到自己,默认没有
	this.pos.forEach(function(value){//forEach方法遍历数组的，value是数组的每个值
		if(value[0] == nextPos[0] && value[1] == nextPos[1]){
			selfCollied = true;
		}
	});
	if(selfCollied){
		console.log("撞到了自己！");
		this.strategies.die.call(this); 
		return;    //return返回一个函数值，阻止函数继续往下执行，return后面不加任何东西，返回undefined
	}
	
	//下一个点是围墙，撞到墙，游戏结束
	if(nextPos[0]<0 || nextPos[1]<0 || nextPos[0]>td-1 || nextPos[1]>tr-1){
		console.log("撞墙上了！");
		this.strategies.die.call(this);
		return;
	}
	
	//下一个点是食物，吃掉变长
	if(food && food.pos[0]==nextPos[0] && food.pos[1] == nextPos[1]){
		//如果这个条件成立说明现在蛇头要走的下一个点是食物的那个点
		this.strategies.eat.call(this);
		return;
	}
	
	//下一个什么都不是，继续走
	this.strategies.move.call(this);   //call方法：回传, 调用完move方法后，返回this(实例对象[之前用的this]),并非调用move()的this.strategies
	
};

//创建一个方法，处理碰撞后的事件
Snake.prototype.strategies = {
	move:function(format){     //format这个参数用于是否删除蛇尾，传了参数代表吃，否则是移动
		/* 创建一个新的身体(在旧蛇头的位置)的对象*/
		var newBody = new Square(this.head.x/sw,this.head.y/sh,"snakeBody");
		/* 更新链表的关系 */
		newBody.first=this.head.first;
		newBody.first.last=newBody;
		newBody.last=newHead;
		/* 把旧蛇头从原来位置删除 */
		this.head.remove();
		/* 把新的身体对象插入到旧蛇头位置 */
		newBody.create();
	
	
		/* 创建一个新的蛇头(下一个要走的点 Nextpos)的对象 */
		var newHead = new Square(this.head.x/sw+this.direction.x,this.head.y/sh + this.direction.y,"snakeHead");
		/* 更新链表的关系 */
		newHead.first=newBody;
		newHead.last=null;
		newHead.viewContent.style.transform="rotate("+this.direction.rotate+'deg)';/*transform 属性向元素应用 2D 或 3D 转换。该属性允许我们对元素进行旋转、缩放、移动或倾斜。
		JavaScript 语法：	object.style.transform="rotate(7deg)"*/
		
		/* 把新的蛇头对象插入到下一个点的位置 */
		newHead.create();
		
		/* 蛇身上每一个方块的坐标更新(newBody相当于旧蛇头不用更新) */
		this.pos.splice(0,0,[this.head.x/sw+this.direction.x,this.head.y/sh + this.direction.y])
		/* 更新蛇头信息 */
		this.head = newHead;
		
		/* 判断是否删除蛇尾 */
		if(!format){ //如果format的值为flase,表示需要删除
			this.tail.remove();
			this.tail = this.tail.last; //数据保存在this.tail中了
			this.pos.pop();
		}
		
	},
	eat:function(){
		this.strategies.move.call(this,true);
		createFood();
		game.score++;
	},
	die:function(){
		//console.log("die");
		game.over();
	}
}


  /* 创建食物 */
function createFood(){
	var x =null;
	var y = null;           //食物的随机坐标
	
	var include = true;     //循环跳出的条件，true表示生成的坐标在蛇身上
	while(include){
		x = Math.round(Math.random()*(td-1));  //round把生成的小数四色五入，math. 是调用
		y = Math.round(Math.random()*(tr-1));
		
		snake.pos.forEach(function(value){   //snake实创全局创建过就有pos属性
			if(x != value[0] && y != value[1]){
				//这个条件表示在蛇身上没有找到
			    include = false;
		    }
		})
	}
	//生成食物
	food = new Square(x,y,"food");    //创造一个方块位置
	food.pos=[x,y];     //存储食物坐标，用于跟蛇头要走的下一个点作对比
	
	var foodDom = document.querySelector(".food");
	if(foodDom){
		foodDom.style.left = x*sw +"px";   
		foodDom.style.top = y*sh + "px";
	}else{
		food.create();      //对应Square，将创造的显示在图上
	}
}

//创建游戏机制
function Game(){
	this.timer = null;
	this.score = 0;
};
//原型中添加init的初始化方法
Game.prototype.init = function(){
	snake.init();
	snake.getNextPos();
	createFood();
	
	document.onkeydown = function(event){
		if(event.which == 37 && snake.direction != snake.directionNum.right){   //按下事件event的which用来判断对应的按键编码    //用户按下左键时，这条蛇不能是往右走
		    snake.direction = snake.directionNum.left;
		}else if(event.which == 38 && snake.direction != snake.directionNum.down){
			snake.direction = snake.directionNum.up;
		}else if(event.which == 39 && snake.direction != snake.directionNum.left){
			snake.direction = snake.directionNum.right;
		}else if(event.which == 40 && snake.direction != snake.directionNum.up){
			snake.direction = snake.directionNum.down;
		}	
	}
	this.start();
};
//原型中添加start游戏开始
Game.prototype.start = function(){
	this.timer = setInterval(function(){
		snake.getNextPos();
	},200)
};
//往Game原型中添加 暂停游戏的方法
Game.prototype.pause = function(){
	clearInterval(this.timer);
};

//往Game原型中添加 结束游戏的方法
Game.prototype.over = function(){
	clearInterval(this.timer);
	alert("你的得分为: "+this.score);
	
	//游戏回到初始状态
	var snakeWrap =document.getElementById("snakeWrap");
	snakeWrap.innerHTML = null;   // 清空蛇和食物
	
	snake = new Snake();     //清空位置,得分等数据
	game = new Game();
	
	var startBtnWrap = document.querySelector(".startBtn");
	startBtnWrap.style.display ='block';
	
}


//开启游戏
snake = new Snake();
game = new Game();
var startBtn = document.querySelector(".startBtn button");   //通过选择器获取元素
startBtn.onclick = function(){
	startBtn.parentNode.style.display="none";
	game.init();
};

//暂停游戏
var snakeWrap = document.getElementById("snakeWrap");
var pauseBtn = document.querySelector(".pauseBtn button");
snakeWrap.onclick =function(){
	game.pause();
	
	pauseBtn.parentNode.style.display = "block";
};
pauseBtn.onclick = function(){
	game.start();
	pauseBtn.parentNode.style.display = "none";
};